package com.leyou.order.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.holders.UserHolder;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.dto.OrderVO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 虎哥
 */
@Slf4j
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderLogisticsMapper logisticsMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Transactional
    public Long createOrder(OrderDTO orderDTO) {
        // 1.新增订单数据
        Order order = new Order();
        // 1.1.订单id信息
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        // 1.2.订单金额信息
        // 1.2.1.获取sku的id集合
        List<Long> idList = orderDTO.getCarts().stream().map(CartDTO::getSkuId).collect(Collectors.toList());
        // 1.2.2.查询sku
        List<SkuDTO> skuList = itemClient.querySkuByIds(idList);
        // 1.2.3.转换cartDTO，变为一个map, key是sku的id，值是num
        Map<Long, Integer> skuMap = orderDTO.getCarts().stream()
                .collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        // 1.2.4.计算金额, 封装OrderDetail
        long total = 0;
        List<OrderDetail> detailList = new ArrayList<>();
        for (SkuDTO sku : skuList) {
            // 获取数量
            Integer num = skuMap.get(sku.getId());
            total += sku.getPrice() * num;
            // 转换sku为OrderDetail
            OrderDetail detail = new OrderDetail();
            detail.setTitle(sku.getTitle());
            detail.setSkuId(sku.getId());
            detail.setPrice(sku.getPrice());
            detail.setNum(num);
            detail.setOwnSpec(sku.getOwnSpec());
            detail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
            detail.setOrderId(orderId);
            detailList.add(detail);
        }
        // 1.2.5.补充order的支付属性
        order.setPostFee(0L);// 全场包邮
        order.setPaymentType(orderDTO.getPaymentType());
        order.setTotalFee(total);
        order.setActualFee(total + order.getPostFee());

        // 1.3.用户信息
        Long userId = UserHolder.getUser().getId();
        order.setUserId(userId);

        // 1.4.订单状态信息
        order.setStatus(OrderStatusEnum.INIT.value());

        // 1.5.写数据库
        orderMapper.insertSelective(order);

        // 2.新增物流数据
        // 2.1.获取物流id
        Long addressId = orderDTO.getAddressId();
        // 2.2.去用户中心，查询这个id对应的地址
        AddressDTO address = userClient.queryAddressById(userId, addressId);
        // 2.3.把地址封装OrderLogistics，写入数据库
        OrderLogistics logistics = BeanHelper.copyProperties(address, OrderLogistics.class);
        logistics.setOrderId(orderId);
        logisticsMapper.insertSelective(logistics);

        // 3.新增订单详情
        detailMapper.insertList(detailList);

        // 4.减库存
        try {
            itemClient.minusStock(skuMap);
        }catch (Exception e){
            log.error("下单失败，商品库存不足！");
            throw new LyException(ExceptionEnum.STOCK_NOT_ENOUGH_ERROR);
        }
        return orderId;
    }

    public OrderVO queryOrderById(Long orderId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        // TODO 查询订单详情OrderDetail，放入 order

        // TODO 查询订单物流信息OrderLogistics，放入 order

        return BeanHelper.copyProperties(order, OrderVO.class);
    }

    @Autowired
    private PayHelper payHelper;

    public String queryPayUrl(Long orderId) {
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        // 校验订单状态
        if(!Objects.equals(order.getStatus(), OrderStatusEnum.INIT.value())){
            // 证明订单已经支付，无需再次获取url
            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
        }
        // 获取金额
        Long total = order.getActualFee();
        // 获取支付地址
        return payHelper.getWxPayUrl(orderId, total);
    }

    @Transactional
    public void handleNotify(Map<String, String> data) {
        // 1.校验签名
        payHelper.isSignValid(data);

        // 2.订单金额校验
        // 2.1.获取data中的订单编号及金额
        String out_trade_no = data.get("out_trade_no");
        String total_fee = data.get("total_fee");
        if(StringUtils.isBlank(out_trade_no) || StringUtils.isBlank(total_fee)){
            throw new RuntimeException("回调参数有误！");
        }
        // 2.2.根据订单编号，到数据库查询订单
        Long orderId = Long.valueOf(out_trade_no);
        Long total = Long.valueOf(total_fee);
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if(order == null){
            throw new RuntimeException("订单编号错误！");
        }
        // 2.3.把查询到的订单金额，跟data中的金额比较
        if(!total.equals(order.getActualFee())){
            // 金额不一致
            throw new RuntimeException("订单金额不一致！");
        }

        // 3.幂等的校验，就是订单状态校验
        if(!OrderStatusEnum.INIT.value().equals(order.getStatus())){
            // 订单已经处理过了
            return;
        }

        // 4.修改订单的支付状态
        Order record = new Order();
        record.setStatus(OrderStatusEnum.PAY_UP.value());
        record.setOrderId(orderId);
        record.setPayTime(new Date());

        int count = orderMapper.updateByPrimaryKeySelective(record);
        if(count != 1){
            throw new RuntimeException("更新失败！");
        }

        log.info("更新订单状态成功。");
    }

    public Integer queryOrderState(Long orderId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if(order == null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }
}
